﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using UnityEngine;

namespace Nirvana
{
    /// <summary>
    /// 控制粒子，动画的播放速度及循环状态，避免不需要的粒子，动画一直在播放
    /// </summary>
    [AddComponentMenu("Nirvana/Effect/Effect Control")]
    public sealed class EffectControl : MonoBehaviour
    {
        private enum EffectMode
        {
            Start,
            Play,
            Resume,
            Paused,
            Stopped
        }

        [SerializeField]
        [Tooltip("Whether this effect is looping.")]
        private bool looping;

        [Tooltip("The delay time when play this effect.")]
        [SerializeField]
        private float delay;

        [Tooltip("The effect duration time.")]
        [SerializeField]
        private float duration = 5f;

        [Tooltip("The effect fade out time.")]
        [SerializeField]
        private float fadeout = 1f;
        private EffectMode effectmode;
        private ParticleSystem[] particlesystems;
        private Animator[] animators;
        private Animation[] animations;
        public bool IsLooping { get { return this.looping; } }
        public bool IsPaused { get { return effectmode == EffectMode.Paused; } }
        public bool IsStopped { get { return effectmode == EffectMode.Start; } }
        public float Duration { get { return this.duration; } }
        public float Fadeout { get { return this.fadeout; } }
        private float curPlaySpeed;
        private float playbackSpeed=1f;
        private Action fadeoutEvent;
        public event Action FadeoutEvent
        {
            [MethodImpl(MethodImplOptions.Synchronized)]
            add
            {
                this.fadeoutEvent +=  value;
            }
            [MethodImpl(MethodImplOptions.Synchronized)]
            remove
            {
                this.fadeoutEvent -= value;
            }
        }
        private Action finishEvent;
        public event Action FinishEvent
        {
            [MethodImpl(MethodImplOptions.Synchronized)]
            add
            {
                this.finishEvent += value;
            }
            [MethodImpl(MethodImplOptions.Synchronized)]
            remove
            {
                this.finishEvent -= value;
            }
        }

        public float PlaybackSpeed
        {
            get { return playbackSpeed; }
            set
            {
                this.playbackSpeed = value;
                FindParticleSystem();
                FindAnimator();
                FindAnimation();
            }
        }

        private void Awake()
        {
            this.particlesystems = base.GetComponentsInChildren<ParticleSystem>(true);
            this.Reset();
        }

        private void LateUpdate()
        {
            if (this.effectmode == EffectMode.Start || this.effectmode == EffectMode.Paused)
            {
                return;
            }
            this.curPlaySpeed += Time.deltaTime * this.playbackSpeed;
            if (this.effectmode == EffectMode.Play && this.curPlaySpeed >= this.delay)
            {
                foreach (ParticleSystem particleSystem in this.FindParticleSystem())
                {
                    particleSystem.Play(false);
                }
                foreach (Animator animator in this.FindAnimator())
                {
                    animator.enabled = false;
                    animator.enabled = true;
                }
                foreach (Animation animation in this.FindAnimation())
                {
                    if (animation.playAutomatically)
                    {
                        animation.enabled = false;
                        animation.enabled = true;
                    }
                    else
                    {
                        animation.Stop();
                        animation.Play();
                    }
                }
                this.effectmode = EffectMode.Resume;
            }
            if (!this.looping && this.effectmode == EffectMode.Resume && this.curPlaySpeed >= this.duration)
            {
                this.Stop();
            }
            if (this.effectmode == EffectMode.Stopped && this.curPlaySpeed >= this.duration + this.fadeout)
            {
                this.effectmode = EffectMode.Start;
                if (this.finishEvent != null)
                {
                    this.finishEvent();
                    this.finishEvent = null;
                }
            }
        }


        public void EstimateDuration()
        {
            this.looping = false;
            this.duration = 0f;
            this.fadeout = 0f;

            foreach (ParticleSystem particleSystem in this.FindParticleSystem())
            {
                if (!(particleSystem == null))
                {
                    if (particleSystem.main.loop)
                    {
                        this.looping = true;
                    }
                    if (this.duration < particleSystem.main.duration)
                    {
                        this.duration = particleSystem.main.duration;
                    }
                    if (this.fadeout < particleSystem.main.startLifetimeMultiplier)
                    {
                        this.fadeout = particleSystem.main.startLifetimeMultiplier;
                    }
                }
            }

            foreach (Animator animator in this.FindAnimator())
            {
                if (!(animator == null))
                {
                    AnimatorStateInfo currentAnimatorStateInfo = animator.GetCurrentAnimatorStateInfo(0);
                    if (currentAnimatorStateInfo.loop)
                    {
                        this.looping = true;
                    }
                    if (this.duration < currentAnimatorStateInfo.length)
                    {
                        this.duration = currentAnimatorStateInfo.length;
                    }
                }
            }

            foreach (Animation animation in this.FindAnimation())
            {
                if (!(animation == null))
                {
                    AnimationClip clip = animation.clip;
                    if (!(clip == null))
                    {
                        if (clip.isLooping)
                        {
                            this.looping = true;
                        }
                        if (this.duration < clip.length)
                        {
                            this.duration = clip.length;
                        }
                    }
                }
            }

        }

        public void Clear()
        {
            this.particlesystems = null;
            this.animations = null;
            this.animators = null;
        }

        public void SimulateInit()
        {
            Animator[] array = this.FindAnimator();
            foreach (Animator animator in array)
            {
                if (!(animator == null))
                {
                    if (!(animator.runtimeAnimatorController == null))
                    {
                        int num = (int)(animator.GetCurrentAnimatorStateInfo(0).length * 30f + 2f);
                        animator.Rebind();
                        animator.StopPlayback();
                        animator.recorderStartTime = 0f;
                        animator.StartRecording(num);
                        for (int j = 0; j < num - 1; j++)
                        {
                            animator.Update((float)j / 30f);
                        }
                        animator.StopRecording();
                        animator.StartPlayback();
                    }
                }
            }
        }

        public void SimulateStart()
        {
            ParticleSystem[] array = this.FindParticleSystem();
            foreach (ParticleSystem particleSystem in array)
            {
                if (!(particleSystem == null))
                {
                    particleSystem.Simulate(0f, false, true);
                    particleSystem.time = 0f;
                    particleSystem.Play();
                }
            }
            Animator[] array3 = this.FindAnimator();
            foreach (Animator animator in array3)
            {
                if (!(animator == null))
                {
                    if (!(animator.runtimeAnimatorController == null))
                    {
                        animator.playbackTime = 0f;
                        animator.Update(0f);
                    }
                }
            }
            Animation[] array5 = this.FindAnimation();
            foreach (Animation animation in array5)
            {
                if (!(animation == null))
                {
                    AnimationClip clip = animation.clip;
                    if (!(clip == null))
                    {
                        clip.SampleAnimation(animation.gameObject, 0f);
                    }
                }
            }
        }

        public void SimulateDelta(float time, float deltaTime)
        {
            ParticleSystem[] array = this.FindParticleSystem();
            foreach (ParticleSystem particleSystem in array)
            {
                if (!(particleSystem == null))
                {
                    particleSystem.Simulate(deltaTime, false, false);
                }
            }
            Animator[] array3 = this.FindAnimator();
            foreach (Animator animator in array3)
            {
                if (!(animator == null))
                {
                    if (!(animator.runtimeAnimatorController == null))
                    {
                        animator.playbackTime = time;
                        animator.Update(0f);
                    }
                }
            }
            Animation[] array5 = this.FindAnimation();
            foreach (Animation animation in array5)
            {
                if (!(animation == null))
                {
                    AnimationClip clip = animation.clip;
                    if (!(clip == null))
                    {
                        clip.SampleAnimation(animation.gameObject, time);
                    }
                }
            }
        }

        public void Simulate(float time)
        {
            Dictionary<ParticleSystem, KeyValuePair<bool, uint>> dictionary = new Dictionary<ParticleSystem, KeyValuePair<bool, uint>>();
            ParticleSystem[] array = this.FindParticleSystem();
            foreach (ParticleSystem particleSystem in array)
            {
                if (!(particleSystem == null))
                {
                    particleSystem.Stop(false);
                    KeyValuePair<bool, uint> value = new KeyValuePair<bool, uint>(particleSystem.useAutoRandomSeed, particleSystem.randomSeed);
                    dictionary.Add(particleSystem, value);
                    if (!particleSystem.isPlaying)
                    {
                        particleSystem.useAutoRandomSeed = false;
                        particleSystem.randomSeed = 0u;
                    }
                    particleSystem.Simulate(0f, false, true);
                    particleSystem.time = 0f;
                    particleSystem.Play();
                }
            }
            for (float num = 0f; num < time; num += 0.02f)
            {
                foreach (ParticleSystem particleSystem2 in array)
                {
                    if (!(particleSystem2 == null))
                    {
                        particleSystem2.Simulate(0.02f, false, false);
                    }
                }
            }
            foreach (ParticleSystem particleSystem3 in array)
            {
                if (!(particleSystem3 == null))
                {
                    particleSystem3.Stop(false);
                    KeyValuePair<bool, uint> keyValuePair = dictionary[particleSystem3];
                    particleSystem3.randomSeed = keyValuePair.Value;
                    particleSystem3.useAutoRandomSeed = keyValuePair.Key;
                }
            }
            Animator[] array5 = this.FindAnimator();
            foreach (Animator animator in array5)
            {
                if (!(animator == null))
                {
                    if (!(animator.runtimeAnimatorController == null))
                    {
                        animator.playbackTime = time;
                        animator.Update(0f);
                    }
                }
            }
            Animation[] array7 = this.FindAnimation();
            foreach (Animation animation in array7)
            {
                if (!(animation == null))
                {
                    AnimationClip clip = animation.clip;
                    if (!(clip == null))
                    {
                        clip.SampleAnimation(animation.gameObject, time);
                    }
                }
            }
        }

        public void Play()
        {
            if (this.effectmode == EffectMode.Resume)
            {
                this.Stop();
            }
            this.effectmode = EffectMode.Play;
        }
        public void Pause()
        {
            if (this.effectmode == EffectMode.Resume)
            {
                foreach (ParticleSystem particleSystem in this.FindParticleSystem())
                {
                    particleSystem.Pause(false);
                }
                foreach (Animator animator in this.FindAnimator())
                {
                    animator.speed = 0f;
                }
                foreach (Animation animation in this.FindAnimation())
                {
                    AnimationClip clip = animation.clip;
                    if (clip != null)
                    {
                        animation[clip.name].speed = 0f;
                    }
                }
                this.effectmode = EffectMode.Paused;
            }
        }

        public void Resume()
        {
            if (this.effectmode == EffectMode.Paused)
            {
                foreach (ParticleSystem particleSystem in this.FindParticleSystem())
                {
                    particleSystem.Play(false);
                }
                foreach (Animator animator in this.FindAnimator())
                {
                    animator.speed = this.playbackSpeed;
                }
                foreach (Animation animation in this.FindAnimation())
                {
                    AnimationClip clip = animation.clip;
                    if (clip != null)
                    {
                        animation[clip.name].speed = this.playbackSpeed;
                    }
                }
                this.effectmode = EffectMode.Resume;
            }
        }

        public void Stop()
        {
            if (this.effectmode != EffectMode.Stopped)
            {
                this.effectmode = EffectMode.Stopped;
                foreach (ParticleSystem particleSystem in this.FindParticleSystem())
                {
                    particleSystem.Stop(false);
                }
                foreach (Animator animator in this.FindAnimator())
                {
                    animator.enabled = false;
                }
                foreach (Animation animation in this.FindAnimation())
                {
                    if (animation.playAutomatically)
                    {
                        animation.enabled = false;
                    }
                    else
                    {
                        animation.Stop();
                    }
                }
                if (this.fadeoutEvent != null)
                {
                    this.fadeoutEvent();
                    this.fadeoutEvent = null;
                }
            }
        }

        public void Reset()
        {
            this.curPlaySpeed = 0f;
            this.effectmode = EffectMode.Start;
        }


        private ParticleSystem[] FindParticleSystem()
        {
            if (this.particlesystems == null)
            {
                this.particlesystems = base.GetComponentsInChildren<ParticleSystem>(true);
                foreach (ParticleSystem particleSystem in this.particlesystems)
                {
                    var main = particleSystem.main;
                    main.simulationSpeed = this.playbackSpeed;
                }
            }
            return this.particlesystems;
        }


        private Animator[] FindAnimator()
        {
            if (this.animators == null)
            {
                this.animators = base.GetComponentsInChildren<Animator>(true);
                foreach (Animator animator in this.animators)
                {
                    animator.speed = this.playbackSpeed;
                }
            }
            return this.animators;
        }

        private Animation[] FindAnimation()
        {
            if (this.animations == null)
            {
                this.animations = base.GetComponentsInChildren<Animation>(true);
                foreach (Animation animation in this.animations)
                {
                    AnimationClip clip = animation.clip;
                    if (clip != null)
                    {
                        animation[clip.name].speed = this.playbackSpeed;
                    }
                }
            }
            return this.animations;
        }


    }
}

